package behaviorTree

import (
	"fmt"
	"time"
)

type Action struct {
	*BaseNode
}

func NewAction(name string) *Action {
	rlt := &Action{
		BaseNode: NewBaseNode(name, NodeType_Action),
	}

	rlt.CheckValidationFunc = rlt.checkChild
	rlt.RunningCheckFunc = rlt.runningCheck_

	return rlt
}

func (self *Action) checkChild() (rlt bool, errInfo string) {
	rlt, errInfo = self.checkChildCnt(0)
	return
}

func (self *Action) Enter(data IRuntimeBTData, stateIn NodeState, localDataIn interface{}) (childNode INode, state NodeState, localDataOut interface{}) {
	switch stateIn {
	case BEGIN:
		obj := data.GetData(self.GetName())
		if obj == nil {
			panic("action(" + self.GetName() + ") proc[ func() NodeState ] is nil")
		}
		proc := obj.(func() NodeState)
		return nil, proc(), nil
	}
	return
}

func (self *Action) runningCheck_(data IRuntimeBTData, localDataIn interface{}) (state NodeState, localDataOut interface{}) {
	return data.ActionRunningCheck(self.GetName()), nil
}

///////////////////////////////////////
type ActionNoop struct {
	*BaseNode
}

func NewNoop(name string) *ActionNoop {
	rlt := &ActionNoop{
		BaseNode: NewBaseNode(name, NodeType_ActionNoop),
	}

	rlt.CheckValidationFunc = rlt.checkChild

	return rlt
}

func (self *ActionNoop) checkChild() (rlt bool, errInfo string) {
	rlt, errInfo = self.checkChildCnt(0)
	return
}

func (self *ActionNoop) Enter(data IRuntimeBTData, stateIn NodeState, localDataIn interface{}) (childNode INode, state NodeState, localDataOut interface{}) {
	switch stateIn {
	case BEGIN:
		return nil, SUCCESS, nil
	}
	return
}

/////////////////////////////////////////
type ActionSuccess struct {
	*BaseNode
}

func NewSuccess(name string) *ActionSuccess {
	rlt := &ActionSuccess{
		BaseNode: NewBaseNode(name, NodeType_ActionSuccess),
	}

	rlt.CheckValidationFunc = rlt.checkChild

	return rlt
}

func (self *ActionSuccess) checkChild() (rlt bool, errInfo string) {
	rlt, errInfo = self.checkChildCnt(0)
	return
}

func (self *ActionSuccess) Enter(data IRuntimeBTData, stateIn NodeState, localDataIn interface{}) (childNode INode, state NodeState, localDataOut interface{}) {
	switch stateIn {
	case BEGIN:
		return nil, SUCCESS, nil
	}
	return
}

/////////////////////////////////////////
type ActionFailure struct {
	*BaseNode
}

func NewFailure(name string) *ActionFailure {
	rlt := &ActionFailure{
		BaseNode: NewBaseNode(name, NodeType_ActionFailure),
	}

	rlt.CheckValidationFunc = rlt.checkChild

	return rlt
}

func (self *ActionFailure) checkChild() (rlt bool, errInfo string) {
	rlt, errInfo = self.checkChildCnt(0)
	return
}

func (self *ActionFailure) Enter(data IRuntimeBTData, stateIn NodeState, localDataIn interface{}) (childNode INode, state NodeState, localDataOut interface{}) {
	switch stateIn {
	case BEGIN:
		return nil, FAILURE, nil
	}
	return
}

/////////////////////////////////////////
type ActionWait struct {
	*BaseNode
	t int64
}

func BTSetWaitSpeed(speed float32) {
	if speed <= 0.1 {
		speed = 0.1
	} else if speed > 100.0 {
		speed = 100.0
	}
	g_wait_speed_factor = 1 / speed
}

var g_wait_speed_factor float32 = 1.0

func NewWait(waitT time.Duration) *ActionWait {
	rlt := &ActionWait{
		BaseNode: NewBaseNode(fmt.Sprintf("Wait%d:%s", GetNextId("ActionWait"), waitT), NodeType_ActionWait),
		t:        int64(float64(waitT.Nanoseconds()) * float64(g_wait_speed_factor)),
	}

	rlt.CheckValidationFunc = rlt.checkChild
	rlt.RunningCheckFunc = rlt.runningCheck_

	return rlt
}

func (self *ActionWait) checkChild() (rlt bool, errInfo string) {
	rlt, errInfo = self.checkChildCnt(0)
	return
}

func (self *ActionWait) Enter(data IRuntimeBTData, stateIn NodeState, localDataIn interface{}) (childNode INode, state NodeState, localDataOut interface{}) {
	switch stateIn {
	case BEGIN:
		return nil, RUNNING, time.Now().UnixNano() + self.t
	}
	return
}
func (self *ActionWait) runningCheck_(data IRuntimeBTData, localDataIn interface{}) (state NodeState, localDataOut interface{}) {
	now := time.Now().UnixNano()
	endT := localDataIn.(int64)
	if now >= endT {
		return SUCCESS, nil
	} else {
		return RUNNING, localDataIn
	}
}
